package com.we.risk.attribution.correct;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

import static com.we.risk.attribution.correct.Common.*;

public class CmsRuleInfo {
    public static Logger LOG = LoggerFactory.getLogger(CmsRuleInfo.class);
    // test
    //    public static final String CMSURL =
    // "http://hfq-data-hub.test.rrdbg.com/api/attribution/config";
    //    public static final String CMSURL = "http://172.16.1.125:2295/api/attribution/config";
    // test v2
    public static final String CMSURL = "http://hfq-data-hub.test.rrdbg.com/api/attribution/v2/config";
    // v1 online
//    public static final String CMSURL = "http://hfq-data-hub.haohuan.com/api/attribution/config";
//     v2 online
//    public static final String CMSURL = "http://hfq-data-hub.haohuan.com/api/attribution/v2/config";


    private HashMap<String, LinkedList<BucketInfo>> attribuStgMap;
    private long requesTime;
    private boolean loginEnable = true;
    private boolean auditEnable = true;

    public HashMap<String, LinkedList<BucketInfo>> getAttribuStgMap() {
        return attribuStgMap;
    }

    public CmsRuleInfo(long requesTime) {
        this.requesTime = requesTime;
        this.attribuStgMap = new HashMap<>();
    }

    private void addBucketInfo(String node, BucketInfo info) {
        if(attribuStgMap.containsKey(node)) {
            LinkedList<BucketInfo> bucketInfoLinkedList = attribuStgMap.get(node);
            bucketInfoLinkedList.add(info);
        } else {
            LinkedList<BucketInfo> bucketInfoList = new LinkedList<>();
            bucketInfoList.add(info);
            attribuStgMap.put(node, bucketInfoList);
        }
    }

    private static void fixCmsRuleInfo(JSONObject dataJson, String node, CmsRuleInfo ruleInfo,
                                        String bktStrategyId, String bktStrategyName, int mode)
    {
        try{
            LOG.info("parseBucketStategyJson input: " + dataJson.toString());
            int status = dataJson.getIntValue("status");
            if(status == 0) {
                BucketInfo bucketInfo = new BucketInfo();
                bucketInfo.setAttribuId(dataJson.getString(ATRIBUID));
                bucketInfo.setBucketName(dataJson.getString(BUCKETNAME));
                bucketInfo.setBucketId(dataJson.getIntValue(BUCKETID));
                bucketInfo.setPercent(dataJson.getIntValue(PERCENT));
                bucketInfo.setBktStrategyId(bktStrategyId);
                bucketInfo.setBktStrategyName(bktStrategyName);
                bucketInfo.setMode(mode);
                ruleInfo.addBucketInfo(node, bucketInfo);
            }
        } catch (Exception e) {
            LOG.info("parseBucketStategyJson Exep: "+ e.getMessage());
            e.printStackTrace();
        }
    }

    private static BucketInfo parseAttributrJson(JSONObject dataJson) {
        BucketInfo bucketInfo = new BucketInfo();
        try {
            if (dataJson != null) {
                LOG.info("parseAttributrJson input: " + dataJson.toString());

                // 1曝光 2点击
                int supportActions = dataJson.getIntValue(ACTIONS);
                LOG.info("supportActions: " + supportActions);
                if (supportActions != 1 && supportActions != 2) {
                    throw new Exception("supportActions param error！！");
                } else {
                    bucketInfo.setSupportActions(supportActions);
                }

                int adChooseRule = dataJson.getIntValue(ADCHSRULE);
                LOG.info("adChooseRule:" + adChooseRule);
                if (adChooseRule != 1 && adChooseRule != 2) {
                    throw new Exception("adChooseRule param error!!");
                } else {
                    // 按rt_type进行映射 adChooseRule 1:最早 2:最晚
                    bucketInfo.setAdChooseRule(adChooseRule - 1);
                }

                int dateDiff = dataJson.getIntValue(TIMEBEFORE);
                LOG.info("dateDiff: " + dateDiff);
                if (dateDiff < 0 || dateDiff > 30) {
                    throw new Exception("timeBefore param error！！");
                } else {
                    bucketInfo.setDateDiff(dateDiff);
                }

                JSONObject supportClass = dataJson.getJSONObject(SUPPORTCLASS);
                if (supportClass != null) {
                    Iterator<String> keysIterator = supportClass.keySet().iterator();
                    while (keysIterator.hasNext()) {
                        String next = keysIterator.next();
                        if (next != null && ("MA".equals(next) || "H5".equals(next))) {
                            if ("MA".equals(next)) {
                                String ma = supportClass.getString("MA");
                                bucketInfo.setMa(ma);
                                LOG.info("MA:" + ma);
                            } else {
                                String h5 = supportClass.getString("H5");
                                bucketInfo.setH5(h5);
                                LOG.info("H5:" + h5);
                            }
                        }
                    }
                }

                JSONArray uids = dataJson.getJSONArray(UIDS);
                if (uids != null) {
                    LOG.info("uids: " + uids.toJSONString());
                    String tmpuids = "";
                    int size = uids.size();
                    for (int ix = 0; ix < size; ix++) {
                        int uid = uids.getIntValue(ix);
                        tmpuids += uid;
                    }
                    bucketInfo.setUids(tmpuids);
                }

                JSONArray targetChannels = dataJson.getJSONArray(TARGETCHANNEL);
                if (targetChannels != null && targetChannels.size() > 0) {
                    LOG.info("targetChannels: " + targetChannels.toJSONString());
                    int targetChannelSize = targetChannels.size();

                    HashSet<String> targets = new HashSet<>();
                    for (int ix = 0; ix < targetChannelSize; ix++) {
                        targets.add(targetChannels.getString(ix));
                    }

                    JSONArray tmpChannelPritory = dataJson.getJSONArray(CHANNELPRITORY);
                    if (tmpChannelPritory != null && tmpChannelPritory.size() > 0) {
                        LOG.info("channelPritory: " + tmpChannelPritory.toJSONString());
                        JSONArray resJsonArray = new JSONArray();
                        for (int ix = 0; ix < tmpChannelPritory.size(); ix++) {
                            String tmpChannel = tmpChannelPritory.getString(ix);
                            if (targets.contains(tmpChannel)) {
                                resJsonArray.add(tmpChannel);
                            }
                        }
                        LOG.info("ResChannelPritory: " + resJsonArray.toJSONString());
                        bucketInfo.setChannel(resJsonArray);

                    } else {
                        throw new Exception("CMS Rule channelPritory null or size 0!!");
                    }
                }

                String attribuId = dataJson.getString(ATRIBUID);
                if (attribuId != null) {
                    LOG.info("attribuId: " + attribuId);
                    bucketInfo.setAttribuId(attribuId);
                } else {
                    LOG.info("CMS Rule ATRIBUID null !!");
                }

                String attribuName = dataJson.getString(ATRIBUNAME);
                if (attribuName != null) {
                    LOG.info("attribuName: " + attribuName);
                    bucketInfo.setAttribuName(attribuName);
                } else {
                    throw new Exception("CMS Rule ATRIBUNAME null !!");
                }

                String node = dataJson.getString(NODE);
                if (node != null && ("login".equals(node) || "audit".equals(node))) {
                    LOG.info("node: " + node);
                    bucketInfo.setNode(node);
                } else {
                    throw new Exception("CMS Rule NODE excep !! node: " + node);
                }
                //解析桶相关信息
                JSONObject bucketJson = dataJson.getJSONObject(CMSV2FLAG);
                if (bucketJson != null) {
                    String strategyId = bucketJson.getString(BKTSTRATEGYID);
                    if (strategyId != null) {
                        LOG.info("strategyId: " + strategyId);
                        bucketInfo.setBktStrategyId(strategyId);
                    } else {
                        throw new Exception("CMS Rule STRATEGYID excep !!");
                    }

                    String strategyName = bucketJson.getString(BKTSTRATEGYNAME);
                    if (strategyName != null) {
                        LOG.info("strategyName: " + strategyName);
                        bucketInfo.setBktStrategyName(strategyName);
                    } else {
                        throw new Exception("CMS Rule STRATEGYNAME excep !!");
                    }

                    String bucketName = bucketJson.getString(BUCKETNAME);
                    if (bucketName != null) {
                        LOG.info("bucketName: " + bucketName);
                        bucketInfo.setBucketName(bucketName);
                    } else {
                        LOG.info("CMS Rule BUCKETNAME excep !!");
                    }

                    int bucketId = bucketJson.getIntValue(BUCKETID);
                    if (bucketId >= 1 && bucketId <= 10) {
                        LOG.info("bucketId: " + bucketId);
                        bucketInfo.setBucketId(bucketId);
                    } else {
                        throw new Exception("CMS Rule BUCKETID excep, bucketId: " + bucketId);
                    }

                    //单实验多桶percent需校验和 = 100%
                    int percent = bucketJson.getIntValue(PERCENT);
                    if (percent >= 0 && percent <= 100 && percent % 10 == 0) {
                        LOG.info("percent: " + percent);
                        bucketInfo.setPercent(percent);
                    } else {
                        LOG.info("CMS Rule PERCENT excep, percent: " + percent);
                    }

                    int mode = bucketJson.getIntValue(MODE);
                    if (mode == 1 || mode == 2) {
                        LOG.info("mode: " + mode);
                        bucketInfo.setMode(mode);
                    } else {
                        throw new Exception("CMS Rule MODE excep, mode: " + mode);
                    }

                    if (mode == 2) {
                        int postbackId = bucketJson.getIntValue(POSTBACKID);
                        if (postbackId >= 1 && postbackId <= 10) {
                            LOG.info("postbackId: " + postbackId);
                            bucketInfo.setPostBackId(postbackId);
                        } else {
                            throw new Exception("CMS Rule POSTBACKID excep, postbackId: " + postbackId);
                        }
                    }
                } else {
                    throw new Exception("CMS Rule CMSV2FLAG excep !!");
                }
            } else {
                throw new Exception("CMS Rule targetChannels null or size 0!!");
            }
        } catch (Exception e) {
            LOG.info("parseAttributrJson excep: " + e.getMessage());
            LOG.info("parseAttributrJson excep: " + e.toString());
            e.printStackTrace();
            bucketInfo = null;
        } finally {
            return bucketInfo;
        }
    }

    private static CmsRuleInfo parseCmsRule(JSONObject input) {
        long requestTime = input.getLongValue(REQUESTIME);
        CmsRuleInfo ruleInfo = new CmsRuleInfo(requestTime);
        try {
            JSONObject data = input.getJSONObject("data");
            if (data != null) {
                LOG.info("data: " + data.toString());
                JSONArray attributeStrategyInfo = data.getJSONArray("attributeStrategyInfo");
                if (attributeStrategyInfo == null) {
                    throw new Exception("CMS Rule attributeStrategyInfo is null !!");
                } else {
                    int size = attributeStrategyInfo.size();
                    if(size == 0) {
                        LOG.error("CMS Rule attributeStrategyInfo size = 0 !");
                        ruleInfo.disableAllNode();
                    } else {
                        for (int i = 0; i < size; i++) {
                            BucketInfo bucketInfo = parseAttributrJson(attributeStrategyInfo.getJSONObject(i));
                            if(bucketInfo != null) {
                                ruleInfo.addBucketInfo(bucketInfo.getNode(), bucketInfo);
                            }
                        }
                    }
                }

                //将没有绑定归因策略的桶修复到list中
                JSONArray bucketStrategyInfo = data.getJSONArray("bucketStrategyInfo");
                if(bucketStrategyInfo == null) {
                    throw new Exception("CMS Rule bucketStrategyInfo is null !!");
                } else {
                    int size = bucketStrategyInfo.size();
                    if(size > 2) {
                        throw new Exception("CMS Rule attributeStrategyInfo size = " + size + " !!");
                    } else {
                        for (int i = 0; i < size; i++) {
                            JSONObject bucketStrategy = bucketStrategyInfo.getJSONObject(i);
                            if (bucketStrategy != null) {
                                LOG.info("bucketStrategy: " + bucketStrategy.toString());
                                String node = bucketStrategy.getString(NODE);
                                String bucketStrategyId = bucketStrategy.getString("_id");
                                String bucketStrategyName = bucketStrategy.getString("name");
                                int mode = bucketStrategy.getIntValue(MODE);
                                JSONArray buckets = bucketStrategy.getJSONArray(BUCKETS);
                                if(buckets != null) {
                                    int bucketSize = buckets.size();
                                    if (bucketSize > 0 && bucketSize <= 10) {
                                        for (int j = 0; j < bucketSize; j++) {
                                            fixCmsRuleInfo(buckets.getJSONObject(j), node, ruleInfo, bucketStrategyId, bucketStrategyName, mode);
                                        }
                                    } else {
                                        ruleInfo.disableNode(node);
                                        LOG.error("Node: " + node + " bucket size: " + size + " error!");
                                    }
                                } else {
                                    ruleInfo.disableNode(node);
                                    LOG.error("Node: " + node +" buckets is null!!");
                                }
                            }
                        }
                    }
                }
            } else {
                throw new Exception("CMS Rule Data Null!!");
            }
            //校验cms配置 单模式所有bucket percent 合是否为100%
            HashMap<String, LinkedList<BucketInfo>> attribuStgMap = ruleInfo.getAttribuStgMap();
            int size = attribuStgMap.size();
            //最多只有登录+归因 两套归因策略
            if (size > 2) {
                throw new Exception("CMS Rule Strategy error, size: " + size);
            } else {
                Iterator<String> nodeIterator = attribuStgMap.keySet().iterator();
                while (nodeIterator.hasNext()) {
                    String node = nodeIterator.next();
                    LinkedList<BucketInfo> bucketInfoLinkedList = attribuStgMap.get(node);
                    int bucketCnt = bucketInfoLinkedList.size();
                    if (bucketCnt <= 0 || bucketCnt > 10) {
                        ruleInfo.disableNode(node);
                        LOG.error("CMS Rule Strategy error, node: " + node + " bucketCnt:" + bucketCnt);
                    } else {
                        BucketInfo first = bucketInfoLinkedList.getFirst();
                        int mode = first.getMode();
                        if (mode == 1) {
                            int percentSum = 0;
                            for (int i = 0; i < bucketCnt; i++) {
                                BucketInfo bucketInfo = bucketInfoLinkedList.get(i);
                                percentSum += bucketInfo.getPercent();
                            }
                            if (percentSum != 100) {
                                ruleInfo.disableNode(node);
                                LOG.error("CMS Rule Strategy percentSum error, node: " + node + " percentSum: " + percentSum);
                            }
                        }
                    }
                }
            }

        } catch (Exception e) {
            LOG.error("Excep: " + e.getMessage());
            e.printStackTrace();
            ruleInfo = null;
        } finally {
            return ruleInfo;
        }
    }


    public static CmsRuleInfo getCmsRuleInfo() {
        CmsRuleInfo cmsRuleInfo = null;
        try {
            int retry = 3;
            JSONObject resJson = new JSONObject();
            while (retry > 0) {
                resJson = requestCmsRule();
                //                String fakeCmsRule =
                // "{\"requestTime\":1677214848874,\"code\":0,\"data\":[{\"timeBefore\":30,\"adChooseRule\":2,\"creator\":\"wangying33\",\"supportTargetChannels\":[\"toutiao\",\"baidu\",\"tencent\",\"kuaishou\"],\"supportClass\":{\"MA\":\"__all__\",\"H5\":\"hfq03,hfq04,hfq05,hfq21,hfq06\"},\"releaseAt\":\"2023-02-22T16:00:00.000Z\",\"operator\":\"fanwenpeng\",\"createdAt\":\"2023-02-08T10:34:46.623Z\",\"supportActions\":2,\"isDeleted\":false,\"uids\":[0,2,4,5,6,8],\"__v\":32,\"name\":\"测试数仓使用5\",\"_id\":\"63e37ac69fbc342e6d8101a5\",\"channelPritory\":[\"kuaishou\",\"toutiao\",\"baidu\",\"tencent\"],\"targetChannels\":[\"kuaishou\",\"baidu\",\"toutiao\",\"tencent\"],\"status\":1,\"updatedAt\":\"2023-02-22T07:38:52.377Z\"}],\"statusCode\":200}";
                //                resJson = JSONObject.parseObject(fakeCmsRule);
                LOG.info("requestCmsRule: " + resJson);
                if (resJson != null
                        && resJson.containsKey(STATUSCODE)
                        && resJson.getIntValue(STATUSCODE) == 200) {
                    // 解析拿到的cms配置
                    LOG.info("be parseCmsRule!!");
                    cmsRuleInfo = parseCmsRule(resJson);
                    break;
                }
                Thread.sleep(2000);
                retry -= 1;
            }
        } catch (Exception e) {
            LOG.error("getCmsRuleInfo excep: " + e.toString());
        }
        return cmsRuleInfo;
    }

    private static JSONObject requestCmsRule() {
        JSONObject param = new JSONObject();
        param.put("username", "dwrtd");
        // 定义接收数据
        JSONObject result = new JSONObject();

        try {
            HttpPost httpPost = new HttpPost(CMSURL);
            CloseableHttpClient client = HttpClients.createDefault();
            // 请求参数转JOSN字符串
            StringEntity entity = new StringEntity(param.toString());
            //        entity.setContentEncoding("UTF-8");
            entity.setContentType("application/json");
            httpPost.setEntity(entity);

            HttpResponse response = client.execute(httpPost);
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == 200) {
                String output = EntityUtils.toString(response.getEntity(), "UTF-8");
                result = JSONObject.parseObject(output);
                result.put(STATUSCODE, 200);
                result.put(REQUESTIME, System.currentTimeMillis());
            } else {
                result.put(STATUSCODE, statusCode);
            }
        } catch (Exception e) {
            LOG.error("excep: " + e.toString());
            result.put(STATUSCODE, -999);
        }
        return result;
    }

    public long getRequesTime() {
        return requesTime;
    }

    private boolean isLoginEnable() {
        return loginEnable;
    }

    private boolean isAuditEnable() {
        return auditEnable;
    }

    private void setLoginEnable(boolean loginEnable) {
        this.loginEnable = loginEnable;
    }

    private void setAuditEnable(boolean auditEnable) {
        this.auditEnable = auditEnable;
    }

    public boolean isNodeEnabel(String node) {
        boolean res = false;
        if("audit".equals(node)) {
            res = isAuditEnable();
        }
        if("login".equals(node)) {
            res = isLoginEnable();
        }
        return res;
    }

    public void disableAllNode(){
        setAuditEnable(false);
        setLoginEnable(false);
    }

    public void disableNode(String node) {
        if("audit".equals(node)) {
            setAuditEnable(false);
        }
        if("login".equals(node)) {
            setLoginEnable(false);
        }
    }

    @Override
    public String toString() {
        JSONObject resJson = new JSONObject();
        String res = "ruleInfo MapSize: " + attribuStgMap.size();
        Set<String> keySet = attribuStgMap.keySet();
        if(keySet != null) {
            Iterator<String> nodeIterator = keySet.iterator();

            while (nodeIterator.hasNext()) {
                String node = nodeIterator.next();
                LOG.info("##node: " + node + " isEnable: " + isNodeEnabel(node));
                LinkedList<BucketInfo> bucketInfoLinkedList = attribuStgMap.get(node);
                JSONArray jsonArray = new JSONArray();
                int size = bucketInfoLinkedList.size();
                LOG.info("##size: " + size);
                if(size > 0) {
                    for (int i = 0; i < size; i++) {
                        BucketInfo bucketInfo = bucketInfoLinkedList.get(i);
                        jsonArray.add(bucketInfo.toString());
                    }
                    resJson.put(node, jsonArray);
                }
            }
            if(resJson.size() > 0) {
                res = resJson.toString();
            }
        }

        return res;
    }

    public static void main(String[] args) {
        String input = "{\"code\":0,\"data\":{\"attributeStrategyInfo\":[{\"_id\":\"64412f30da395d0105e2e8bd\",\"supportClass\":{\"H5\":\"\",\"MA\":\"__all__\"},\"uids\":[0],\"targetChannels\":[\"toutiao\",\"baidu\"],\"supportTargetChannels\":[],\"channelPritory\":[\"toutiao\",\"baidu\"],\"status\":1,\"releaseAt\":\"2023-04-20T16:00:00.000Z\",\"isDeleted\":false,\"node\":\"login\",\"name\":\"0420验收登录归因-曝光-0-头条＞百度-T-2-末次\",\"bucketInfo\":{\"strategyId\":\"64412e83410dee014cc0a225\",\"strategyName\":\"0420验收登录归因_归因行为-曝光vs归因行为-点击\",\"mode\":2,\"id\":1,\"name\":\"归因行为-曝光\",\"percent\":100,\"postBackId\":1},\"supportActions\":1,\"timeBefore\":2,\"adChooseRule\":2,\"operator\":\"cuilidan\",\"creator\":\"cuilidan\",\"createdAt\":\"2023-04-20T12:25:20.920Z\",\"updatedAt\":\"2023-04-20T12:25:30.033Z\",\"__v\":0},{\"_id\":\"64412f7511aa3301a9082aa0\",\"supportClass\":{\"H5\":\"\",\"MA\":\"__all__\"},\"uids\":[1],\"targetChannels\":[\"toutiao\",\"baidu\"],\"supportTargetChannels\":[],\"channelPritory\":[\"toutiao\",\"baidu\"],\"status\":1,\"releaseAt\":\"2023-04-20T16:00:00.000Z\",\"isDeleted\":false,\"node\":\"login\",\"name\":\"0420验收登录归因-点击-1-头条＞百度-T-2-末次\",\"bucketInfo\":{\"strategyId\":\"64412e83410dee014cc0a225\",\"strategyName\":\"0420验收登录归因_归因行为-曝光vs归因行为-点击\",\"mode\":2,\"id\":2,\"name\":\"归因行为-点击\",\"percent\":100,\"postBackId\":1},\"supportActions\":2,\"timeBefore\":2,\"adChooseRule\":2,\"operator\":\"cuilidan\",\"creator\":\"cuilidan\",\"createdAt\":\"2023-04-20T12:26:29.172Z\",\"updatedAt\":\"2023-04-20T12:26:40.552Z\",\"__v\":0}],\"bucketStrategyInfo\":[{\"_id\":\"64412e83410dee014cc0a225\",\"status\":1,\"releaseAt\":\"2023-04-20T16:00:00.000Z\",\"node\":\"login\",\"name\":\"0420验收登录归因_归因行为-曝光vs归因行为-点击\",\"mode\":2,\"bucketes\":[{\"status\":1,\"_id\":\"64412e83410dee014cc0a226\",\"name\":\"归因行为-曝光\",\"percent\":100,\"id\":1},{\"status\":1,\"_id\":\"64412e83410dee014cc0a227\",\"name\":\"归因行为-点击\",\"percent\":100,\"id\":2}],\"operator\":\"cuilidan\",\"creator\":\"cuilidan\",\"updatedAt\":\"2023-04-20T12:26:40.542Z\",\"createdAt\":\"2023-04-20T12:22:27.502Z\",\"__v\":0}]}}";
        JSONObject inputJson = JSONObject.parseObject(input);
        CmsRuleInfo cmsRuleInfo = parseCmsRule(inputJson);

        System.out.println("test: " + cmsRuleInfo.toString());
    }
}
